import React, {CSSProperties} from "react";
import {Input, Select as AntdSelect, Form as AntdForm,} from 'antd';
import {VJsonComponent} from "../../factory";
import _ from 'lodash'
import {YvanEvent} from "../../types";
import {apply, YvanEventBind, YvanEventDispatch} from "../../utils/helper";
import {DataComponentProp} from "../../datasource";
import {FormItemBaseState, FormItemVJSon, VJsonFormItemBase} from "./VJsonFormItemBase";
import * as Extend from '../../extend'
import {toJS} from "mobx";

const {Option: AntdOption} = AntdSelect;

export interface SelectVJsonProp extends FormItemVJSon<Select> {
    /**
     * multiple / tags 多个值的情况下，值的分隔符
     */
    valueSpliter: string

    customFilter?: (sender: Select, keyword: string, option: { value: string, label: string }) => boolean

    addonAfter?: string | React.ReactNode
    addonBefore?: string | React.ReactNode

    //支持清除
    allowClear?: boolean
    //是否在选中项后清空搜索框，只在 mode 为 multiple 或 tags 时有效	boolean	true
    autoClearSearchValue?: boolean
    //默认获取焦点	boolean	false
    autoFocus?: boolean
    //是否有边框	boolean	true
    bordered?: boolean
    //自定义的多选框清空图标	ReactNode	-
    clearIcon?: React.ReactNode
    //是否默认高亮第一个选项	boolean	true
    defaultActiveFirstOption?: boolean
    //是否默认展开下拉菜单	boolean	-
    defaultOpen?: boolean
    //指定默认选中的条目	string | string[]
    defaultValue?: string | string[]
    //是否禁用	boolean	false
    disabled?: boolean
    //下拉菜单的 className 属性	string	-
    dropdownClassName?: string
    //下拉菜单和选择器同宽。默认将设置 min-width，当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动	boolean | number	true
    dropdownMatchSelectWidth?: boolean | number
    //下拉菜单的 style 属性	CSSProperties	-
    dropdownStyle?: CSSProperties
    //设置弹窗滚动高度	number	256
    listHeight?: number
    //最多显示多少个 tag	number	-
    maxTagCount?: number
    //最大显示的 tag 文本长度	number	-
    maxTagTextLength?: number
    //设置 Select 的模式为多选或标签	multiple | tags	-
    mode?: 'multiple' | 'tags'

    // 选中 option，或 input 的 value 变化时，调用此函数	function(value, option:Option | Array<Option>)	-
    onChange?: YvanEvent<Select>
    //清除内容时回调	function	-	4.6.0
    onClear?: YvanEvent<Select>
    //取消选中时调用，参数为选中项的 value (或 key) 值，仅在 multiple 或 tags 模式下生效	function(string | number | LabeledValue)	-
    onDeselect?: YvanEvent<Select>
    //展开下拉菜单的回调	function(open)	-
    onDropdownVisibleChange?: YvanEvent<Select>

    //按键按下时回调	function	-
    onInputKeyDown?: YvanEvent<Select>
    //鼠标移入时回调
    onMouseEnter?: YvanEvent<Select>
    //鼠标移出时回调	function	-
    onMouseLeave?: YvanEvent<Select>
    //文本框值变化时回调	function(value: string)	-
    onSearch?: YvanEvent<Select>
    //被选中时调用，参数为选中项的 value (或 key) 值	function(string | number | LabeledValue, option: Option)	-
    onSelect?: YvanEvent<Select>
    //是否展开下拉菜单	boolean	-
    open?: boolean
    className?: string
    //选择框默认文字	string	-
    placeholder?: string
    //选择框大小
    size?: 'large' | 'middle' | 'small'
    //自定义的选择框后缀图标
    suffixIcon?: React.ReactNode
}

export interface SelectVJsonDataProp extends SelectVJsonProp, DataComponentProp<Select> {

}

export interface SelectState extends FormItemBaseState<Select> {

}

@VJsonComponent({
    view: 'select'
})
//@ts-ignore
export default class Select extends VJsonFormItemBase<Select, SelectVJsonDataProp, SelectState> {
    static defaultProps = {
        ...VJsonFormItemBase.defaultProps,
        allowClear: true,
        idField: 'value',
        labelField: 'label',
        data: [],
        rules: [],
        visible: true,
        valueSpliter: ',',
        className:''
    }

    constructor(props: any) {
        super(props, Select.defaultProps);

        if (this.valueIsArray()) {
            this.defaultValue = this.valueSplit(this.defaultValue)
        }
    }

    private valueSplit(value?: string | string[]) {
        if (_.isArray(value)) {
            return value
        }
        if (!value) {
            return []
        }
        return value.split(this.props.vjson.valueSpliter)
    }

    private valueJoin(value?: string | string[]) {
        if (_.isArray(value)) {
            return value.join(this.props.vjson.valueSpliter)
        }
        if (!value) {
            return ''
        }
        return value
    }

    private valueIsArray() {
        return (this.props.vjson.mode === 'multiple' || this.props.vjson.mode === 'tags')
    }

    get mode() {
        return this.props.vjson.mode
    }

    set mode(v) {
        const me = this
        const form = me.state.$formRef?.current;
        if (form) {
            const value = (v === 'multiple' || v === 'tags') ? me.valueSplit(this.value) : me.valueJoin(this.value)
            form.setFields([
                {
                    name: this.formItemName,
                    value: value
                }
            ])
        }
        this.props.vjson.mode = v
    }

    private _filterOption(filterWord: any, option: any) {
        const {value, children: label} = option

        if (typeof this.props.vjson.customFilter === 'function') {
            return YvanEventDispatch(this.props.vjson.customFilter, this, filterWord,
                {
                    value,
                    label
                }
            )
        }

        if (!filterWord) {
            return true
        }

        return Extend.keywordFilter(filterWord, label, value)
    }

    protected onValueChange(value: any) {
        value = this.valueJoin(value)
        if (value !== this.value) {
            this.value = value
            YvanEventDispatch(this.props.vjson.onChange, this, value)
        }
    }

    /**
     * 从控件值到实体 (control -> entity) 的转换 normalizeToEntity
     */
    normalizeToEntity(value: any) {
        if (this.valueIsArray()) {
            return this.valueJoin(value)
        }
        return value
    }

    /**
     * 从实体值到控件 (entity -> control) 的转换 normalizeToEntity
     */
    normalizeToControl(value: any) {
        if (this.valueIsArray()) {
            return this.valueSplit(value)
        } else {
            return this.valueJoin(value)
        }
    }

    protected get _isRootFormItem() {
        return false
    }

    protected renderWrapper(): JSX.Element {
        if (Extend.isDebugMode()) {
            console.log('RenderSelect', this.toString())
        }

        const addonAfter =
            (typeof this.props.vjson.addonAfter === 'undefined')
                ? null
                : (<span className="ant-input-group-addon">
                        {
                            apply(this, this.props.vjson.addonAfter)
                        }
                </span>)
        return (
            <span className='ant-input-group-wrapper'>
                <span className="ant-input-wrapper ant-input-group">
                    <AntdForm.Item noStyle
                                   {...this._getFormItemBindProperty(false)}
                    >
                        {/*@ts-ignore*/}
                        <AntdSelect key={this.key} view_id={this.key} aria-roledescription={this.view}
                                    className={apply(this, this.props.vjson.className)}
                                    showSearch={true}
                                    filterOption={this._filterOption.bind(this)}

                                    allowClear={apply(this, this.props.vjson.allowClear)}
                                    autoClearSearchValue={apply(this, this.props.vjson.autoClearSearchValue)}
                                    autoFocus={apply(this, this.props.vjson.autoFocus)}
                                    bordered={apply(this, this.props.vjson.bordered)}
                                    clearIcon={this.props.vjson.clearIcon}
                                    defaultActiveFirstOption={this.props.vjson.defaultActiveFirstOption}
                                    defaultOpen={this.props.vjson.defaultOpen}
                                    disabled={apply(this, this.props.vjson.disabled)}
                                    dropdownClassName={"select-z-index " + _.trim(apply(this, this.props.vjson.dropdownClassName))}
                                    // dropdownClassName={this.props.vjson.dropdownClassName}
                                    dropdownMatchSelectWidth={this.props.vjson.dropdownMatchSelectWidth}
                                    dropdownStyle={toJS(this.props.vjson.dropdownStyle)}
                                    listHeight={this.props.vjson.listHeight}
                                    loading={this.loading}
                                    maxTagCount={apply(this, this.props.vjson.maxTagCount)}
                                    maxTagTextLength={apply(this, this.props.vjson.maxTagTextLength)}
                                    mode={apply(this, this.props.vjson.mode)}
                                    onBlur={YvanEventBind(this.props.vjson.onBlur, this)}
                                    onChange={this.onValueChange.bind(this)}
                                    onClear={YvanEventBind(this.props.vjson.onClear, this)}
                                    onDropdownVisibleChange={YvanEventBind(this.props.vjson.onDropdownVisibleChange, this)}
                                    onFocus={YvanEventBind(this.props.vjson.onFocus, this)}
                                    onInputKeyDown={YvanEventBind(this.props.vjson.onInputKeyDown, this)}
                                    onMouseEnter={YvanEventBind(this.props.vjson.onMouseEnter, this)}
                                    onMouseLeave={YvanEventBind(this.props.vjson.onMouseLeave, this)}
                                    onSelect={YvanEventBind(this.props.vjson.onSelect, this)}
                                    open={this.props.vjson.open}
                                    placeholder={apply(this, this.props.vjson.placeholder)}
                                    size={apply(this, this.props.vjson.size)}
                                    suffixIcon={apply(this, this.props.vjson.suffixIcon)}
                        >
                            {
                                ..._.map(this.data, (item) => {
                                    const value = '' + item[this.props.vjson.idField || 'value']
                                    const label = '' + item[this.props.vjson.labelField || 'label']
                                    return (
                                        <AntdOption key={value}
                                                    value={value}
                                        >{label}</AntdOption>
                                    )
                                })
                            }
                        </AntdSelect>
                    </AntdForm.Item>
                    {
                        addonAfter
                    }
                </span>
            </span>
        )
    }
}
